package jmine.tec.report.base.persist.auditoria;

import static jmine.tec.report.base.ReportBaseMessages.BUNDLE_NAME;
import static jmine.tec.report.base.ReportBaseMessages.RELATORIO_TRILHA_AUDITORIA;

import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jmine.tec.report.api.Report;
import jmine.tec.report.base.AbstractReportCreator;
import jmine.tec.report.impl.ReportBuilder;
import jmine.tec.report.impl.table.ReportTableBuilder;
import jmine.tec.utils.Tuple;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;

import bancosys.tec.exception.MessageHolder;
import bancosys.tec.persist.audit.dao.AuditVersionDAO;
import bancosys.tec.persist.audit.domain.AuditValuedProperty;
import bancosys.tec.persist.audit.domain.AuditVersion;
import bancosys.tec.persist.dataset.HibernateRandomAccessResultSet;
import bancosys.tec.utils.date.Date;
import bancosys.tec.utils.date.DateUtils;
import bancosys.tec.utils.date.Timestamp;

/**
 * Relatório de trilhas de auditoria.
 * 
 * @author Renan Kuroki
 * @date Jan 12, 2011
 */
public class TrilhaAuditoriaReportCreator extends AbstractReportCreator<TrilhaAuditoriaReportParameter> {

    private static final Pattern PATTER_WEB_AUDIT_SOURCE = Pattern.compile("<web@(.*)>");

    private static final Pattern PATTER_JMS_AUDIT_SOURCE = Pattern.compile("<MDB@(.*)>");

    public static final String DEFAULT_DATE_FORMAT = "dd/MM/yyyy HH:mm";

    /**
     * Construtor
     */
    public TrilhaAuditoriaReportCreator() {
        super(TrilhaAuditoriaReportParameter.class);
    }

    /**
     * {@inheritDoc}
     */
    public String getCreatorKey() {
        return RELATORIO_TRILHA_AUDITORIA;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<Tuple<String, Report>> doCreateReports(TrilhaAuditoriaReportParameter parameter) {
        MessageHolder messageHolder = new MessageHolder(BUNDLE_NAME, this.getCreatorKey());
        ReportBuilder reportBuilder = new ReportBuilder(messageHolder.getMessage(), this.getFileName("trilha_auditoria", parameter));

        // Configurando HEADER
        if (parameter.getClasseAuditavel() != null) {
            reportBuilder.addHeaderStringParameter("cadastro", "Cadastro", parameter.getClasseAuditavelNome());
        }

        String usuario = parameter.getUsuario() == null ? "" : parameter.getUsuario();
        if (!StringUtils.isEmpty(usuario)) {
            reportBuilder.addHeaderStringParameter("usuario", "Usuario", usuario);
        }

        if (parameter.getDataInicio() != null && parameter.getDataFim() != null) {
            String periodo =
                    String.format("%s até %s", DateUtils.dateToStringDDMMYYYY(parameter.getDataInicio()),
                            DateUtils.dateToStringDDMMYYYY(parameter.getDataFim()));
            reportBuilder.addHeaderStringParameter("periodo", "Período", periodo);
        }

        // Adicionando Tabelas
        AuditVersionDAO auditVersionDAO = this.getController().getDAOFactory().getDAOByClass(AuditVersionDAO.class);
        AuditVersion example = auditVersionDAO.createBean();
        Date beginDate = parameter.getDataInicio();
        Date endDate = parameter.getDataFim();
        Timestamp beginTimestamp = new Timestamp(beginDate.getYear(), beginDate.getMonth(), beginDate.getDay(), 0, 0, 0, 0);
        Timestamp endTimestamp = new Timestamp(endDate.getYear(), endDate.getMonth(), endDate.getDay() + 1, 0, 0, 0, 0);
        String className = parameter.getClasseAuditavel() == null ? null : parameter.getClasseAuditavel().getName();

        HibernateRandomAccessResultSet<AuditVersion> audits =
                auditVersionDAO.findResultSetByClassByNameByDateReverseSorted(example, className, usuario, beginTimestamp, endTimestamp);

        // Criar a tabela
        Iterator<AuditVersion> auditsIterator = audits.iterator();
        while (auditsIterator.hasNext()) {
            AuditVersion auditVersion = auditsIterator.next();
            if (auditVersion.getFormattedProperties().iterator().hasNext()) {

                ReportTableBuilder<AuditValuedProperty> builder =
                        reportBuilder.createTableBuilder(AuditValuedProperty.class, "Trilha Auditoria" + auditVersion.getId());
                builder.setRecords(auditVersion.getFormattedProperties());

                // Header
                String data = DateFormatUtils.format(auditVersion.getTs().getTime(), DEFAULT_DATE_FORMAT);
                builder.addTableHeader("Cadastro: " + auditVersion.getEntity().getName());
                builder.addTableHeader("Id: " + auditVersion.getEntity().getEntityId());
                builder.addTableHeader("Evento: " + auditVersion.getAction().getNomeAuditoria());
                builder.addTableHeader("Usuário: " + auditVersion.getUser());
                builder.addTableHeader("Data: " + data);

                this.extrairURLVersao(builder, auditVersion);

                // Table
                builder.addStringColumn("campo", "Campo", "name");
                builder.addStringColumn("dadosAntes", "Dados Antes", "oldValue");
                builder.addStringColumn("dadosApos", "Dados Após", "newValue");

                // Footer
                builder.addFooterLabel("campo", auditVersion.getStatus());

                builder.close();
            }
        }

        return this.pack("Trilha Auditoria", parameter, reportBuilder.createReport());
    }

    /**
     * Adiciona os campos especificos do tellus.
     * 
     * @param builder {@link ReportTableBuilder}
     * @param auditVersion {@link AuditVersion}
     */
    private void extrairURLVersao(ReportTableBuilder<AuditValuedProperty> builder, AuditVersion auditVersion) {
        Matcher matcher = PATTER_WEB_AUDIT_SOURCE.matcher(auditVersion.getModificationSource());
        if (matcher.matches()) {
            builder.addTableHeader("Endereço IP: " + matcher.group(1));
        } else {
            matcher = PATTER_JMS_AUDIT_SOURCE.matcher(auditVersion.getModificationSource());
            if (matcher.matches()) {
                builder.addTableHeader("Fila JMS: " + matcher.group(1));
            } else {
                builder.addTableHeader("Origem: " + auditVersion.getModificationSource());
            }
        }
    }
}
